#pragma once

#include <array>
#include <functional>
#include <memory>
#include <string>
#include <vector>

#include <wayland-client.hpp>

struct zwlr_screencopy_manager_v1;
struct zwlr_screencopy_frame_v1;

namespace wayland
{
class zwlr_screencopy_manager_v1_t;
class zwlr_screencopy_frame_v1_t;
enum class zwlr_screencopy_frame_v1_error : uint32_t;
struct zwlr_screencopy_frame_v1_flags;

namespace detail
{
extern const wl_interface zwlr_screencopy_manager_v1_interface;
extern const wl_interface zwlr_screencopy_frame_v1_interface;
}

/** \brief manager to inform clients and begin capturing

      This object is a manager which offers requests to start capturing from a
      source.

*/
class zwlr_screencopy_manager_v1_t : public proxy_t
{
private:
    struct events_t : public detail::events_base_t
    {
    };

    static int dispatcher(uint32_t opcode, const std::vector<detail::any> &args, const std::shared_ptr<detail::events_base_t> &e);

    zwlr_screencopy_manager_v1_t(proxy_t const &wrapped_proxy, construct_proxy_wrapper_tag /*unused*/);

public:
    zwlr_screencopy_manager_v1_t();
    explicit zwlr_screencopy_manager_v1_t(const proxy_t &proxy);
    zwlr_screencopy_manager_v1_t(zwlr_screencopy_manager_v1 *p, wrapper_type t = wrapper_type::standard);

    zwlr_screencopy_manager_v1_t proxy_create_wrapper();

    static const std::string interface_name;

    operator zwlr_screencopy_manager_v1 *() const;

    /** \brief capture an output
        \param overlay_cursor composite cursor onto the frame
        \param output

          Capture the next frame of an entire output.

    */
    zwlr_screencopy_frame_v1_t capture_output(int32_t overlay_cursor, output_t const &output);

    /** \brief Minimum protocol version required for the \ref capture_output function
     */
    static constexpr std::uint32_t capture_output_since_version = 1;

    /** \brief capture an output's region
        \param overlay_cursor composite cursor onto the frame
        \param output
        \param x
        \param y
        \param width
        \param height

          Capture the next frame of an output's region.

          The region is given in output logical coordinates, see
          xdg_output.logical_size. The region will be clipped to the output's
          extents.

    */
    zwlr_screencopy_frame_v1_t capture_output_region(int32_t overlay_cursor, output_t const &output, int32_t x, int32_t y, int32_t width, int32_t height);

    /** \brief Minimum protocol version required for the \ref capture_output_region function
     */
    static constexpr std::uint32_t capture_output_region_since_version = 1;
};

/** \brief a frame ready for copy

      This object represents a single frame.

      When created, a series of buffer events will be sent, each representing a
      supported buffer type. The "buffer_done" event is sent afterwards to
      indicate that all supported buffer types have been enumerated. The client
      will then be able to send a "copy" request. If the capture is successful,
      the compositor will send a "flags" followed by a "ready" event.

      For objects version 2 or lower, wl_shm buffers are always supported, ie.
      the "buffer" event is guaranteed to be sent.

      If the capture failed, the "failed" event is sent. This can happen anytime
      before the "ready" event.

      Once either a "ready" or a "failed" event is received, the client should
      destroy the frame.

*/
class zwlr_screencopy_frame_v1_t : public proxy_t
{
private:
    struct events_t : public detail::events_base_t
    {
        std::function<void(shm_format, uint32_t, uint32_t, uint32_t)> buffer;
        std::function<void(zwlr_screencopy_frame_v1_flags)> flags;
        std::function<void(uint32_t, uint32_t, uint32_t)> ready;
        std::function<void()> failed;
        std::function<void(uint32_t, uint32_t, uint32_t, uint32_t)> damage;
        std::function<void(uint32_t, uint32_t, uint32_t)> linux_dmabuf;
        std::function<void()> buffer_done;
    };

    static int dispatcher(uint32_t opcode, const std::vector<detail::any> &args, const std::shared_ptr<detail::events_base_t> &e);

    zwlr_screencopy_frame_v1_t(proxy_t const &wrapped_proxy, construct_proxy_wrapper_tag /*unused*/);

public:
    zwlr_screencopy_frame_v1_t();
    explicit zwlr_screencopy_frame_v1_t(const proxy_t &proxy);
    zwlr_screencopy_frame_v1_t(zwlr_screencopy_frame_v1 *p, wrapper_type t = wrapper_type::standard);

    zwlr_screencopy_frame_v1_t proxy_create_wrapper();

    static const std::string interface_name;

    operator zwlr_screencopy_frame_v1 *() const;

    /** \brief copy the frame
        \param buffer

          Copy the frame to the supplied buffer. The buffer must have a the
          correct size, see zwlr_screencopy_frame_v1.buffer and
          zwlr_screencopy_frame_v1.linux_dmabuf. The buffer needs to have a
          supported format.

          If the frame is successfully copied, a "flags" and a "ready" events are
          sent. Otherwise, a "failed" event is sent.

    */
    void copy(buffer_t const &buffer);

    /** \brief Minimum protocol version required for the \ref copy function
     */
    static constexpr std::uint32_t copy_since_version = 1;

    /** \brief copy the frame when it's damaged
        \param buffer

          Same as copy, except it waits until there is damage to copy.

    */
    void copy_with_damage(buffer_t const &buffer);

    /** \brief Minimum protocol version required for the \ref copy_with_damage function
     */
    static constexpr std::uint32_t copy_with_damage_since_version = 2;

    /** \brief Check whether the \ref copy_with_damage function is available with
        the currently bound version of the protocol
    */
    bool can_copy_with_damage() const;

    /** \brief wl_shm buffer information
        \param format buffer format
        \param width buffer width
        \param height buffer height
        \param stride buffer stride

          Provides information about wl_shm buffer parameters that need to be
          used for this frame. This event is sent once after the frame is created
          if wl_shm buffers are supported.

    */
    std::function<void(shm_format, uint32_t, uint32_t, uint32_t)> &on_buffer();

    /** \brief frame flags
        \param flags frame flags

          Provides flags about the frame. This event is sent once before the
          "ready" event.

    */
    std::function<void(zwlr_screencopy_frame_v1_flags)> &on_flags();

    /** \brief indicates frame is available for reading
        \param tv_sec_hi high 32 bits of the seconds part of the timestamp
        \param tv_sec_lo low 32 bits of the seconds part of the timestamp
        \param tv_nsec nanoseconds part of the timestamp

          Called as soon as the frame is copied, indicating it is available
          for reading. This event includes the time at which presentation happened
          at.

          The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples,
          each component being an unsigned 32-bit value. Whole seconds are in
          tv_sec which is a 64-bit value combined from tv_sec_hi and tv_sec_lo,
          and the additional fractional part in tv_nsec as nanoseconds. Hence,
          for valid timestamps tv_nsec must be in [0, 999999999]. The seconds part
          may have an arbitrary offset at start.

          After receiving this event, the client should destroy the object.

    */
    std::function<void(uint32_t, uint32_t, uint32_t)> &on_ready();

    /** \brief frame copy failed

          This event indicates that the attempted frame copy has failed.

          After receiving this event, the client should destroy the object.

    */
    std::function<void()> &on_failed();

    /** \brief carries the coordinates of the damaged region
        \param x damaged x coordinates
        \param y damaged y coordinates
        \param width current width
        \param height current height

          This event is sent right before the ready event when copy_with_damage is
          requested. It may be generated multiple times for each copy_with_damage
          request.

          The arguments describe a box around an area that has changed since the
          last copy request that was derived from the current screencopy manager
          instance.

          The union of all regions received between the call to copy_with_damage
          and a ready event is the total damage since the prior ready event.

    */
    std::function<void(uint32_t, uint32_t, uint32_t, uint32_t)> &on_damage();

    /** \brief linux-dmabuf buffer information
        \param format fourcc pixel format
        \param width buffer width
        \param height buffer height

          Provides information about linux-dmabuf buffer parameters that need to
          be used for this frame. This event is sent once after the frame is
          created if linux-dmabuf buffers are supported.

    */
    std::function<void(uint32_t, uint32_t, uint32_t)> &on_linux_dmabuf();

    /** \brief all buffer types reported

          This event is sent once after all buffer events have been sent.

          The client should proceed to create a buffer of one of the supported
          types, and send a "copy" request.

    */
    std::function<void()> &on_buffer_done();
};

/** \brief

  */
enum class zwlr_screencopy_frame_v1_error : uint32_t {
    /** \brief the object has already been used to copy a wl_buffer */
    already_used = 0,
    /** \brief buffer attributes are invalid */
    invalid_buffer = 1
};

/** \brief

  */
struct zwlr_screencopy_frame_v1_flags : public wayland::detail::bitfield<1, 1>
{
    zwlr_screencopy_frame_v1_flags(const wayland::detail::bitfield<1, 1> &b)
        : wayland::detail::bitfield<1, 1>(b)
    {
    }
    zwlr_screencopy_frame_v1_flags(const uint32_t value)
        : wayland::detail::bitfield<1, 1>(value)
    {
    }
    /** \brief contents are y-inverted */
    static const wayland::detail::bitfield<1, 1> y_invert;
};

}
